package com.boyadegroot.divelog.data;

import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.provider.BaseColumns;

public class DiveLogProvider extends ContentProvider {

    private static final String TAG = DiveLogProvider.class.getName();

    public static final String PATH_DIVERS = "divers";
    public static final String PATH_DIVES = "dives";
    public static final String PATH_SAMPLES = "samples";
    public static final String PATH_CERTS = "certifications";
    public static final String PATH_SITES = "sites";
    public static final String PATH_TRIPS = "trips";
    public static final String PATH_BUDDIES = "buddies";
    public static final String PATH_COURSES = "courses";
    public static final String PATH_CENTERS = "centers";
    public static final String PATH_COUNTRIES = "countries";
    public static final String PATH_LOCATIONS = "locations";
    public static final String PATH_ORGANIZATIONS = "organizations";

    private static final String PATH_DIVER_ID = PATH_DIVERS + "/#";
    private static final String PATH_DIVE_ID = PATH_DIVES + "/#";
    private static final String PATH_SAMPLE_ID = PATH_SAMPLES + "/#";
    private static final String PATH_CERT_ID = PATH_CERTS + "/#";
    private static final String PATH_SITE_ID = PATH_SITES + "/#";
    private static final String PATH_TRIP_ID = PATH_TRIPS + "/#";
    private static final String PATH_BUDDY_ID = PATH_BUDDIES + "/#";
    private static final String PATH_COURSE_ID = PATH_COURSES + "/#";
    private static final String PATH_CENTER_ID = PATH_CENTERS + "/#";
    private static final String PATH_COUNTRY_ID = PATH_COUNTRIES + "/#";
    private static final String PATH_LOCATION_ID = PATH_LOCATIONS + "/#";
    private static final String PATH_ORGANIZATION_ID = PATH_ORGANIZATIONS + "/#";

    public static final String PATH_DIVERS_COUNT = PATH_DIVERS + "/count";
    public static final String PATH_DIVES_COUNT = PATH_DIVES + "/count";
    public static final String PATH_SAMPLES_COUNT = PATH_SAMPLES + "/count";
    public static final String PATH_CERTS_COUNT = PATH_CERTS + "/count";
    public static final String PATH_SITES_COUNT = PATH_SITES + "/count";
    public static final String PATH_TRIPS_COUNT = PATH_TRIPS + "/count";
    public static final String PATH_BUDDIES_COUNT = PATH_BUDDIES + "/count";
    public static final String PATH_COURSES_COUNT = PATH_COURSES + "/count";
    public static final String PATH_CENTERS_COUNT = PATH_CENTERS + "/count";
    public static final String PATH_COUNTRIES_COUNT = PATH_COUNTRIES + "/count";
    public static final String PATH_LOCATIONS_COUNT = PATH_LOCATIONS + "/count";
    public static final String PATH_ORGANIZATIONS_COUNT = PATH_ORGANIZATIONS + "/count";
    
    public static final String PATH_DIVERSTATS_TOTALBOTTOMTIME = PATH_DIVERS + "/#/totalbottomtime";
    public static final String PATH_DIVERSTATS_MINIMALSI = PATH_DIVERS + "/#/minimalsi";
    public static final String PATH_DIVERSTATS_DEEPESTDIVE = PATH_DIVERS + "/#/deepestdive";
    public static final String PATH_DIVERSTATS_SHALLOWESTDIVE = PATH_DIVERS + "/#/shallowestdive";
    public static final String PATH_DIVERSTATS_COLDESTDIVE = PATH_DIVERS + "/#/coldestdive";
    public static final String PATH_DIVERSTATS_WARMESTDIVE = PATH_DIVERS + "/#/warmestdive";

    public static final String PATH_DIVERRES_LOCATIONS = PATH_DIVERS + "/#/locations";

    public static final String AUTHORITY = "com.boyadegroot.divelog.provider";
    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY);

    private static final int MATCH_DIVERS = 1;
    private static final int MATCH_DIVES = 2;
    private static final int MATCH_SAMPLES = 3;
    private static final int MATCH_CERTS = 4;
    private static final int MATCH_SITES = 5;
    private static final int MATCH_TRIPS = 6;
    private static final int MATCH_BUDDIES = 7;
    private static final int MATCH_COURSES = 8;
    private static final int MATCH_CENTERS = 9;
    private static final int MATCH_COUNTRIES = 10;
    private static final int MATCH_LOCATIONS = 11;
    private static final int MATCH_ORGANIZATIONS = 12;

    private static final int MATCH_DIVER_ID = 101;
    private static final int MATCH_DIVE_ID = 102;
    private static final int MATCH_SAMPLE_ID = 103;
    private static final int MATCH_CERT_ID = 104;
    private static final int MATCH_SITE_ID = 105;
    private static final int MATCH_TRIP_ID = 106;
    private static final int MATCH_BUDDY_ID = 107;
    private static final int MATCH_COURSE_ID = 108;
    private static final int MATCH_CENTER_ID = 109;
    private static final int MATCH_COUNTRY_ID = 110;
    private static final int MATCH_LOCATION_ID = 111;
    private static final int MATCH_ORGANIZATION_ID = 112;

    private static final int MATCH_DIVERS_COUNT = 201;
    private static final int MATCH_DIVES_COUNT = 202;
    private static final int MATCH_SAMPLES_COUNT = 203;
    private static final int MATCH_CERTS_COUNT = 204;
    private static final int MATCH_SITES_COUNT = 205;
    private static final int MATCH_TRIPS_COUNT = 206;
    private static final int MATCH_BUDDIES_COUNT = 207;
    private static final int MATCH_COURSES_COUNT = 208;
    private static final int MATCH_CENTERS_COUNT = 209;
    private static final int MATCH_COUNTRIES_COUNT = 210;
    private static final int MATCH_LOCATIONS_COUNT = 211;
    private static final int MATCH_ORGANIZATIONS_COUNT = 212;

    private static final int MATCH_DIVERSTATS_TOTALBOTTOMTIME = 301;
    private static final int MATCH_DIVERSTATS_MINIMALSI = 302;
    private static final int MATCH_DIVERSTATS_DEEPESTDIVE = 303;
    private static final int MATCH_DIVERSTATS_SHALLOWESTDIVE = 304;
    private static final int MATCH_DIVERSTATS_COLDESTDIVE = 305;
    private static final int MATCH_DIVERSTATS_WARMESTDIVE = 306;

    private static final int MATCH_DIVERRES_LOCATIONS = 401;

    private static final UriMatcher sUriMatcher;

    static {
        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

        sUriMatcher.addURI(AUTHORITY, PATH_DIVERS, MATCH_DIVERS);
        sUriMatcher.addURI(AUTHORITY, PATH_DIVES, MATCH_DIVES);
        sUriMatcher.addURI(AUTHORITY, PATH_SAMPLES, MATCH_SAMPLES);
        sUriMatcher.addURI(AUTHORITY, PATH_CERTS, MATCH_CERTS);
        sUriMatcher.addURI(AUTHORITY, PATH_SITES, MATCH_SITES);
        sUriMatcher.addURI(AUTHORITY, PATH_TRIPS, MATCH_TRIPS);
        sUriMatcher.addURI(AUTHORITY, PATH_BUDDIES, MATCH_BUDDIES);
        sUriMatcher.addURI(AUTHORITY, PATH_COURSES, MATCH_COURSES);
        sUriMatcher.addURI(AUTHORITY, PATH_CENTERS, MATCH_CENTERS);
        sUriMatcher.addURI(AUTHORITY, PATH_COUNTRIES, MATCH_COUNTRIES);
        sUriMatcher.addURI(AUTHORITY, PATH_LOCATIONS, MATCH_LOCATIONS);
        sUriMatcher.addURI(AUTHORITY, PATH_ORGANIZATIONS, MATCH_ORGANIZATIONS);

        sUriMatcher.addURI(AUTHORITY, PATH_DIVER_ID, MATCH_DIVER_ID);
        sUriMatcher.addURI(AUTHORITY, PATH_DIVE_ID, MATCH_DIVE_ID);
        sUriMatcher.addURI(AUTHORITY, PATH_SAMPLE_ID, MATCH_SAMPLE_ID);
        sUriMatcher.addURI(AUTHORITY, PATH_CERT_ID, MATCH_CERT_ID);
        sUriMatcher.addURI(AUTHORITY, PATH_SITE_ID, MATCH_SITE_ID);
        sUriMatcher.addURI(AUTHORITY, PATH_TRIP_ID, MATCH_TRIP_ID);
        sUriMatcher.addURI(AUTHORITY, PATH_BUDDY_ID, MATCH_BUDDY_ID);
        sUriMatcher.addURI(AUTHORITY, PATH_COURSE_ID, MATCH_COURSE_ID);
        sUriMatcher.addURI(AUTHORITY, PATH_CENTER_ID, MATCH_CENTER_ID);
        sUriMatcher.addURI(AUTHORITY, PATH_COUNTRY_ID, MATCH_COUNTRY_ID);
        sUriMatcher.addURI(AUTHORITY, PATH_LOCATION_ID, MATCH_LOCATION_ID);
        sUriMatcher.addURI(AUTHORITY, PATH_ORGANIZATION_ID, MATCH_ORGANIZATION_ID);

        sUriMatcher.addURI(AUTHORITY, PATH_DIVERS_COUNT, MATCH_DIVERS_COUNT);
        sUriMatcher.addURI(AUTHORITY, PATH_DIVES_COUNT, MATCH_DIVES_COUNT);
        sUriMatcher.addURI(AUTHORITY, PATH_SAMPLES_COUNT, MATCH_SAMPLES_COUNT);
        sUriMatcher.addURI(AUTHORITY, PATH_CERTS_COUNT, MATCH_CERTS_COUNT);
        sUriMatcher.addURI(AUTHORITY, PATH_SITES_COUNT, MATCH_SITES_COUNT);
        sUriMatcher.addURI(AUTHORITY, PATH_TRIPS_COUNT, MATCH_TRIPS_COUNT);
        sUriMatcher.addURI(AUTHORITY, PATH_BUDDIES_COUNT, MATCH_BUDDIES_COUNT);
        sUriMatcher.addURI(AUTHORITY, PATH_COURSES_COUNT, MATCH_COURSES_COUNT);
        sUriMatcher.addURI(AUTHORITY, PATH_CENTERS_COUNT, MATCH_CENTERS_COUNT);
        sUriMatcher.addURI(AUTHORITY, PATH_COUNTRIES_COUNT, MATCH_COUNTRIES_COUNT);
        sUriMatcher.addURI(AUTHORITY, PATH_LOCATIONS_COUNT, MATCH_LOCATIONS_COUNT);
        sUriMatcher.addURI(AUTHORITY, PATH_ORGANIZATIONS_COUNT, MATCH_ORGANIZATIONS_COUNT);

        sUriMatcher.addURI(AUTHORITY, PATH_DIVERSTATS_TOTALBOTTOMTIME, MATCH_DIVERSTATS_TOTALBOTTOMTIME);
        sUriMatcher.addURI(AUTHORITY, PATH_DIVERSTATS_MINIMALSI, MATCH_DIVERSTATS_MINIMALSI);
        sUriMatcher.addURI(AUTHORITY, PATH_DIVERSTATS_DEEPESTDIVE, MATCH_DIVERSTATS_DEEPESTDIVE);
        sUriMatcher.addURI(AUTHORITY, PATH_DIVERSTATS_SHALLOWESTDIVE, MATCH_DIVERSTATS_SHALLOWESTDIVE);
        sUriMatcher.addURI(AUTHORITY, PATH_DIVERSTATS_COLDESTDIVE, MATCH_DIVERSTATS_COLDESTDIVE);
        sUriMatcher.addURI(AUTHORITY, PATH_DIVERSTATS_WARMESTDIVE, MATCH_DIVERSTATS_WARMESTDIVE);

        sUriMatcher.addURI(AUTHORITY, PATH_DIVERRES_LOCATIONS, MATCH_DIVERRES_LOCATIONS);
    }

    private DiveLogDatabaseHelper mDatabaseHelper;

    @Override
    public boolean onCreate() {
        Context context = getContext();
        mDatabaseHelper = new DiveLogDatabaseHelper(context);
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        // Log.v(TAG, "query(uri = " + uri + ", projection = " + projection + ", selection = " + selection + ", selectionArgs = " + selectionArgs + ", sortOrder = " + sortOrder + ")");
        Cursor cursor;
        int uriType = sUriMatcher.match(uri);
        switch (uriType) {
            case MATCH_DIVERS:
                cursor = queryDatabase(DiveLogDatabaseContract.Divers.TABLE_NAME, projection, selection, selectionArgs, sortOrder);
                break;
            case MATCH_DIVES:
                cursor = queryDatabase(DiveLogDatabaseContract.Dives.TABLE_NAME, projection, selection, selectionArgs, sortOrder);
                break;
            case MATCH_SAMPLES:
                cursor = queryDatabase(DiveLogDatabaseContract.DiveSamples.TABLE_NAME, projection, selection, selectionArgs, sortOrder);
                break;
            case MATCH_CERTS:
                cursor = queryDatabase(DiveLogDatabaseContract.DiveCertifications.TABLE_NAME, projection, selection, selectionArgs, sortOrder);
                break;
            case MATCH_SITES:
                cursor = queryDatabase(DiveLogDatabaseContract.DiveSites.TABLE_NAME, projection, selection, selectionArgs, sortOrder);
                break;
            case MATCH_TRIPS:
                cursor = queryDatabase(DiveLogDatabaseContract.DiveTrips.TABLE_NAME, projection, selection, selectionArgs, sortOrder);
                break;
            case MATCH_BUDDIES:
                cursor = queryDatabase(DiveLogDatabaseContract.DiveBuddies.TABLE_NAME, projection, selection, selectionArgs, sortOrder);
                break;
            case MATCH_COURSES:
                cursor = queryDatabase(DiveLogDatabaseContract.DiveCourses.TABLE_NAME, projection, selection, selectionArgs, sortOrder);
                break;
            case MATCH_CENTERS:
                cursor = queryDatabase(DiveLogDatabaseContract.DiveCenters.TABLE_NAME, projection, selection, selectionArgs, sortOrder);
                break;
            case MATCH_COUNTRIES:
                cursor = queryDatabase(DiveLogDatabaseContract.DiveCountries.TABLE_NAME, projection, selection, selectionArgs, sortOrder);
                break;
            case MATCH_LOCATIONS:
                cursor = queryDatabase(DiveLogDatabaseContract.DiveLocations.TABLE_NAME, projection, selection, selectionArgs, sortOrder);
                break;
            case MATCH_ORGANIZATIONS:
                cursor = queryDatabase(DiveLogDatabaseContract.DiveOrganizations.TABLE_NAME, projection, selection, selectionArgs, sortOrder);
                break;
            case MATCH_DIVER_ID:
                cursor = queryDatabaseId(DiveLogDatabaseContract.Divers.TABLE_NAME, projection, uri.getLastPathSegment());
                break;
            case MATCH_DIVE_ID:
                cursor = queryDatabaseId(DiveLogDatabaseContract.Dives.TABLE_NAME, projection, uri.getLastPathSegment());
                break;
            case MATCH_SAMPLE_ID:
                cursor = queryDatabaseId(DiveLogDatabaseContract.DiveSamples.TABLE_NAME, projection, uri.getLastPathSegment());
                break;
            case MATCH_CERT_ID:
                cursor = queryDatabaseId(DiveLogDatabaseContract.DiveCertifications.TABLE_NAME, projection, uri.getLastPathSegment());
                break;
            case MATCH_SITE_ID:
                cursor = queryDatabaseId(DiveLogDatabaseContract.DiveSites.TABLE_NAME, projection, uri.getLastPathSegment());
                break;
            case MATCH_TRIP_ID:
                cursor = queryDatabaseId(DiveLogDatabaseContract.DiveTrips.TABLE_NAME, projection, uri.getLastPathSegment());
                break;
            case MATCH_BUDDY_ID:
                cursor = queryDatabaseId(DiveLogDatabaseContract.DiveBuddies.TABLE_NAME, projection, uri.getLastPathSegment());
                break;
            case MATCH_COURSE_ID:
                cursor = queryDatabaseId(DiveLogDatabaseContract.DiveCourses.TABLE_NAME, projection, uri.getLastPathSegment());
                break;
            case MATCH_CENTER_ID:
                cursor = queryDatabaseId(DiveLogDatabaseContract.DiveCenters.TABLE_NAME, projection, uri.getLastPathSegment());
                break;
            case MATCH_COUNTRY_ID:
                cursor = queryDatabaseId(DiveLogDatabaseContract.DiveCountries.TABLE_NAME, projection, uri.getLastPathSegment());
                break;
            case MATCH_LOCATION_ID:
                cursor = queryDatabaseId(DiveLogDatabaseContract.DiveLocations.TABLE_NAME, projection, uri.getLastPathSegment());
                break;
            case MATCH_ORGANIZATION_ID:
                cursor = queryDatabaseId(DiveLogDatabaseContract.DiveOrganizations.TABLE_NAME, projection, uri.getLastPathSegment());
                break;
            case MATCH_DIVERS_COUNT:
                cursor = queryDatabaseCount(DiveLogDatabaseContract.Divers.TABLE_NAME, selection, selectionArgs);
                break;
            case MATCH_DIVES_COUNT:
                cursor = queryDatabaseCount(DiveLogDatabaseContract.Dives.TABLE_NAME, selection, selectionArgs);
                break;
            case MATCH_SAMPLES_COUNT:
                cursor = queryDatabaseCount(DiveLogDatabaseContract.DiveSamples.TABLE_NAME, selection, selectionArgs);
                break;
            case MATCH_CERTS_COUNT:
                cursor = queryDatabaseCount(DiveLogDatabaseContract.DiveCertifications.TABLE_NAME, selection, selectionArgs);
                break;
            case MATCH_SITES_COUNT:
                cursor = queryDatabaseCount(DiveLogDatabaseContract.DiveSites.TABLE_NAME, selection, selectionArgs);
                break;
            case MATCH_TRIPS_COUNT:
                cursor = queryDatabaseCount(DiveLogDatabaseContract.DiveTrips.TABLE_NAME, selection, selectionArgs);
                break;
            case MATCH_BUDDIES_COUNT:
                cursor = queryDatabaseCount(DiveLogDatabaseContract.DiveBuddies.TABLE_NAME, selection, selectionArgs);
                break;
            case MATCH_COURSES_COUNT:
                cursor = queryDatabaseCount(DiveLogDatabaseContract.DiveCourses.TABLE_NAME, selection, selectionArgs);
                break;
            case MATCH_CENTERS_COUNT:
                cursor = queryDatabaseCount(DiveLogDatabaseContract.DiveCenters.TABLE_NAME, selection, selectionArgs);
                break;
            case MATCH_COUNTRIES_COUNT:
                cursor = queryDatabaseCount(DiveLogDatabaseContract.DiveCountries.TABLE_NAME, selection, selectionArgs);
                break;
            case MATCH_LOCATIONS_COUNT:
                cursor = queryDatabaseCount(DiveLogDatabaseContract.DiveLocations.TABLE_NAME, selection, selectionArgs);
                break;
            case MATCH_ORGANIZATIONS_COUNT:
                cursor = queryDatabaseCount(DiveLogDatabaseContract.DiveOrganizations.TABLE_NAME, selection, selectionArgs);
                break;
            case MATCH_DIVERSTATS_TOTALBOTTOMTIME:
                cursor = queryTotalBottomTime(uri.getPathSegments().get(1));
                break;
            case MATCH_DIVERSTATS_MINIMALSI:
                cursor = queryMinimalSi(uri.getPathSegments().get(1));
                break;
            case MATCH_DIVERSTATS_DEEPESTDIVE:
                cursor = queryDeepestDive(uri.getPathSegments().get(1));
                break;
            case MATCH_DIVERSTATS_SHALLOWESTDIVE:
                cursor = queryShallowestDive(uri.getPathSegments().get(1));
                break;
            case MATCH_DIVERSTATS_COLDESTDIVE:
                cursor = queryColdestDive(uri.getPathSegments().get(1));
                break;
            case MATCH_DIVERSTATS_WARMESTDIVE:
                cursor = queryWarmestDive(uri.getPathSegments().get(1));
                break;
            case MATCH_DIVERRES_LOCATIONS:
                cursor = queryDiverLocations(uri.getPathSegments().get(1), sortOrder);
                break;
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
        return cursor;
    }

    private Cursor queryTotalBottomTime(String diverId) {
        SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
        String[] selectionArgs = new String[] { diverId };
        Cursor cursor = db.rawQuery(
                "SELECT SUM(" + DiveLogDatabaseContract.Dives.COLUMN_NAME_DURATION + ")" +
                        " AS " + DiveLogDatabaseContract.COLUMN_NAME_STAT +
                        " FROM " + DiveLogDatabaseContract.Dives.TABLE_NAME +
                        " WHERE " + DiveLogDatabaseContract.Dives.COLUMN_NAME_DIVER_ID + " = ?",
                selectionArgs);
        return cursor;
    }

    private Cursor queryMinimalSi(String diverId) {
        SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
        String[] selectionArgs = new String[] { diverId };
        Cursor cursor = db.rawQuery(
                "SELECT *, MIN(" + DiveLogDatabaseContract.Dives.COLUMN_NAME_SURFACEINTERVAL + ")" +
                        " AS " + DiveLogDatabaseContract.COLUMN_NAME_STAT +
                        " FROM " + DiveLogDatabaseContract.Dives.TABLE_NAME +
                        " WHERE " + DiveLogDatabaseContract.Dives.COLUMN_NAME_DIVER_ID + " = ?",
                selectionArgs);
        return cursor;
    }

    private Cursor queryDeepestDive(String diverId) {
        SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
        String[] selectionArgs = new String[] { diverId };
        Cursor cursor = db.rawQuery(
                "SELECT *, MAX(" + DiveLogDatabaseContract.Dives.COLUMN_NAME_MAXDEPTH + ")" +
                        " AS " + DiveLogDatabaseContract.COLUMN_NAME_STAT +
                        " FROM " + DiveLogDatabaseContract.Dives.TABLE_NAME +
                        " WHERE " + DiveLogDatabaseContract.Dives.COLUMN_NAME_DIVER_ID + " = ?",
                selectionArgs);
        return cursor;
    }

    private Cursor queryShallowestDive(String diverId) {
        SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
        String[] selectionArgs = new String[] { diverId };
        Cursor cursor = db.rawQuery(
                "SELECT *, MIN(" + DiveLogDatabaseContract.Dives.COLUMN_NAME_MAXDEPTH + ")" +
                        " AS " + DiveLogDatabaseContract.COLUMN_NAME_STAT +
                        " FROM " + DiveLogDatabaseContract.Dives.TABLE_NAME +
                        " WHERE " + DiveLogDatabaseContract.Dives.COLUMN_NAME_DIVER_ID + " = ?",
                selectionArgs);
        return cursor;
    }

    private Cursor queryColdestDive(String diverId) {
        SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
        String[] selectionArgs = new String[] { diverId };
        Cursor cursor = db.rawQuery(
                "SELECT *, MIN(" + DiveLogDatabaseContract.Dives.COLUMN_NAME_BOTTOMTEMP + ")" +
                        " AS " + DiveLogDatabaseContract.COLUMN_NAME_STAT +
                        " FROM " + DiveLogDatabaseContract.Dives.TABLE_NAME +
                        " WHERE " + DiveLogDatabaseContract.Dives.COLUMN_NAME_DIVER_ID + " = ?",
                selectionArgs);
        return cursor;
    }

    private Cursor queryWarmestDive(String diverId) {
        SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
        String[] selectionArgs = new String[] { diverId };
        Cursor cursor = db.rawQuery(
                "SELECT *, MAX(" + DiveLogDatabaseContract.Dives.COLUMN_NAME_BOTTOMTEMP + ")" +
                        " AS " + DiveLogDatabaseContract.COLUMN_NAME_STAT +
                        " FROM " + DiveLogDatabaseContract.Dives.TABLE_NAME +
                        " WHERE " + DiveLogDatabaseContract.Dives.COLUMN_NAME_DIVER_ID + " = ?",
                selectionArgs);
        return cursor;
    }

    private Cursor queryDiverLocations(String diverId, String sortOrder) {
        SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
        String[] selectionArgs = new String[] { diverId };
        String rawQuery = "SELECT DISTINCT " +
            DiveLogDatabaseContract.DiveLocations.TABLE_NAME + "." + DiveLogDatabaseContract.DiveLocations._ID + "," +
            DiveLogDatabaseContract.DiveLocations.TABLE_NAME + "." + DiveLogDatabaseContract.DiveLocations.COLUMN_NAME_NAME + "," +
            DiveLogDatabaseContract.DiveLocations.TABLE_NAME + "." + DiveLogDatabaseContract.DiveLocations.COLUMN_NAME_COUNTRY_ID + "," +
            DiveLogDatabaseContract.DiveLocations.TABLE_NAME + "." + DiveLogDatabaseContract.DiveLocations.COLUMN_NAME_LATITUDE + "," +
            DiveLogDatabaseContract.DiveLocations.TABLE_NAME + "." + DiveLogDatabaseContract.DiveLocations.COLUMN_NAME_LONGITUDE +
            " FROM " + DiveLogDatabaseContract.DiveLocations.TABLE_NAME +
            " LEFT JOIN " + DiveLogDatabaseContract.DiveSites.TABLE_NAME + " ON " + DiveLogDatabaseContract.DiveSites.TABLE_NAME + "." + DiveLogDatabaseContract.DiveSites.COLUMN_NAME_LOCATION_ID + " = " + DiveLogDatabaseContract.DiveLocations.TABLE_NAME + "." + DiveLogDatabaseContract.DiveLocations._ID +
            " LEFT JOIN " + DiveLogDatabaseContract.Dives.TABLE_NAME + " ON " + DiveLogDatabaseContract.Dives.TABLE_NAME + "." + DiveLogDatabaseContract.Dives.COLUMN_NAME_SITE_ID + " = " + DiveLogDatabaseContract.DiveSites.TABLE_NAME + "." + DiveLogDatabaseContract.DiveSites._ID +
            " WHERE " + DiveLogDatabaseContract.Dives.TABLE_NAME + "." + DiveLogDatabaseContract.Dives.COLUMN_NAME_DIVER_ID + " = ?";
        if (sortOrder != null) {
            rawQuery += " ORDER BY " + DiveLogDatabaseContract.DiveLocations.TABLE_NAME + "." + sortOrder;
        }
        Cursor cursor = db.rawQuery(rawQuery, selectionArgs);
        return cursor;
    }

    private Cursor queryDatabaseId(String table, String[] projection, String id) {
        SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
        String selection = BaseColumns._ID + " = ?";
        String[] selectionArgs = new String[] {id};
        Cursor cursor = db.query(
                table,
                projection,
                selection,
                selectionArgs,
                null, // groupBy
                null, // having
                null); // sortOrder
        return cursor;
    }

    private Cursor queryDatabase(String table, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
        Cursor cursor = db.query(
                table,
                projection,
                selection,
                selectionArgs,
                null, // groupBy
                null, // having
                sortOrder);
        return cursor;
    }
    
    private Cursor queryDatabaseCount(String table, String selection, String[] selectionArgs) {
        String query = "SELECT COUNT(*) AS " + DiveLogDatabaseContract.COLUMN_NAME_COUNT + " FROM " + table;
        if (selection != null && selectionArgs != null) {
            query += " WHERE " + selection;
        }
        SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
        Cursor cursor = db.rawQuery(query, selectionArgs);
        return cursor;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        int count;
        int uriType = sUriMatcher.match(uri);
        switch (uriType) {
            case MATCH_DIVERS:
                count = deleteFromDatabase(DiveLogDatabaseContract.Divers.TABLE_NAME, selection, selectionArgs);
                break;
            case MATCH_DIVES:
                count = deleteFromDatabase(DiveLogDatabaseContract.Dives.TABLE_NAME, selection, selectionArgs);
                break;
            case MATCH_SAMPLES:
                count = deleteFromDatabase(DiveLogDatabaseContract.DiveSamples.TABLE_NAME, selection, selectionArgs);
                break;
            case MATCH_CERTS:
                count = deleteFromDatabase(DiveLogDatabaseContract.DiveCertifications.TABLE_NAME, selection, selectionArgs);
                break;
            case MATCH_SITES:
                count = deleteFromDatabase(DiveLogDatabaseContract.DiveSites.TABLE_NAME, selection, selectionArgs);
                break;
            case MATCH_TRIPS:
                count = deleteFromDatabase(DiveLogDatabaseContract.DiveTrips.TABLE_NAME, selection, selectionArgs);
                break;
            case MATCH_BUDDIES:
                count = deleteFromDatabase(DiveLogDatabaseContract.DiveBuddies.TABLE_NAME, selection, selectionArgs);
                break;
            case MATCH_COURSES:
                count = deleteFromDatabase(DiveLogDatabaseContract.DiveCourses.TABLE_NAME, selection, selectionArgs);
                break;
            case MATCH_CENTERS:
                count = deleteFromDatabase(DiveLogDatabaseContract.DiveCenters.TABLE_NAME, selection, selectionArgs);
                break;
            case MATCH_COUNTRIES:
                count = deleteFromDatabase(DiveLogDatabaseContract.DiveCountries.TABLE_NAME, selection, selectionArgs);
                break;
            case MATCH_LOCATIONS:
                count = deleteFromDatabase(DiveLogDatabaseContract.DiveLocations.TABLE_NAME, selection, selectionArgs);
                break;
            case MATCH_ORGANIZATIONS:
                count = deleteFromDatabase(DiveLogDatabaseContract.DiveOrganizations.TABLE_NAME, selection, selectionArgs);
                break;
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
        Context context = getContext();
        ContentResolver resolver = context.getContentResolver();
        resolver.notifyChange(uri, null);
        return count;
    }
    
    private int deleteFromDatabase(String table, String selection, String[] selectionArgs) {
        SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
        int count = db.delete(
                table,
                selection,
                selectionArgs
        );
        return count;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        int count;
        int uriType = sUriMatcher.match(uri);
        switch (uriType) {
            case MATCH_DIVERS:
                count = updateDatabase(DiveLogDatabaseContract.Divers.TABLE_NAME, values, selection, selectionArgs);
                break;
            case MATCH_DIVES:
                count = updateDatabase(DiveLogDatabaseContract.Dives.TABLE_NAME, values, selection, selectionArgs);
                break;
            case MATCH_SAMPLES:
                count = updateDatabase(DiveLogDatabaseContract.DiveSamples.TABLE_NAME, values, selection, selectionArgs);
                break;
            case MATCH_CERTS:
                count = updateDatabase(DiveLogDatabaseContract.DiveCertifications.TABLE_NAME, values, selection, selectionArgs);
                break;
            case MATCH_SITES:
                count = updateDatabase(DiveLogDatabaseContract.DiveSites.TABLE_NAME, values, selection, selectionArgs);
                break;
            case MATCH_TRIPS:
                count = updateDatabase(DiveLogDatabaseContract.DiveTrips.TABLE_NAME, values, selection, selectionArgs);
                break;
            case MATCH_BUDDIES:
                count = updateDatabase(DiveLogDatabaseContract.DiveBuddies.TABLE_NAME, values, selection, selectionArgs);
                break;
            case MATCH_COURSES:
                count = updateDatabase(DiveLogDatabaseContract.DiveCourses.TABLE_NAME, values, selection, selectionArgs);
                break;
            case MATCH_CENTERS:
                count = updateDatabase(DiveLogDatabaseContract.DiveCenters.TABLE_NAME, values, selection, selectionArgs);
                break;
            case MATCH_COUNTRIES:
                count = updateDatabase(DiveLogDatabaseContract.DiveCountries.TABLE_NAME, values, selection, selectionArgs);
                break;
            case MATCH_LOCATIONS:
                count = updateDatabase(DiveLogDatabaseContract.DiveLocations.TABLE_NAME, values, selection, selectionArgs);
                break;
            case MATCH_ORGANIZATIONS:
                count = updateDatabase(DiveLogDatabaseContract.DiveOrganizations.TABLE_NAME, values, selection, selectionArgs);
                break;
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
        Context context = getContext();
        ContentResolver resolver = context.getContentResolver();
        resolver.notifyChange(uri, null);
        return count;
    }

    private int updateDatabase(String table, ContentValues values, String selection, String[] selectionArgs) {
        SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
        int count = db.update(
                table,
                values,
                selection,
                selectionArgs
        );
        return count;
    }
    
    @Override
    public Uri insert(Uri uri, ContentValues values) {
        Uri newUri;
        long id;
        int uriType = sUriMatcher.match(uri);
        switch (uriType) {
            case MATCH_DIVERS:
                id = insertIntoDatabase(DiveLogDatabaseContract.Divers.TABLE_NAME, values);
                newUri = Uri.parse(AUTHORITY + "/" + PATH_DIVERS + "/" + id);
                break;
            case MATCH_DIVES:
                id = insertIntoDatabase(DiveLogDatabaseContract.Dives.TABLE_NAME, values);
                newUri = Uri.parse(AUTHORITY + "/" + PATH_DIVES + "/" + id);
                break;
            case MATCH_SAMPLES:
                id = insertIntoDatabase(DiveLogDatabaseContract.DiveSamples.TABLE_NAME, values);
                newUri = Uri.parse(AUTHORITY + "/" + PATH_SAMPLES + "/" + id);
                break;
            case MATCH_CERTS:
                id = insertIntoDatabase(DiveLogDatabaseContract.DiveCertifications.TABLE_NAME, values);
                newUri = Uri.parse(AUTHORITY + "/" + PATH_CERTS + "/" + id);
                break;
            case MATCH_SITES:
                id = insertIntoDatabase(DiveLogDatabaseContract.DiveSites.TABLE_NAME, values);
                newUri = Uri.parse(AUTHORITY + "/" + PATH_SITES + "/" + id);
                break;
            case MATCH_TRIPS:
                id = insertIntoDatabase(DiveLogDatabaseContract.DiveTrips.TABLE_NAME, values);
                newUri = Uri.parse(AUTHORITY + "/" + PATH_TRIPS + "/" + id);
                break;
            case MATCH_BUDDIES:
                id = insertIntoDatabase(DiveLogDatabaseContract.DiveBuddies.TABLE_NAME, values);
                newUri = Uri.parse(AUTHORITY + "/" + PATH_BUDDIES + "/" + id);
                break;
            case MATCH_COURSES:
                id = insertIntoDatabase(DiveLogDatabaseContract.DiveCourses.TABLE_NAME, values);
                newUri = Uri.parse(AUTHORITY + "/" + PATH_COURSES + "/" + id);
                break;
            case MATCH_CENTERS:
                id = insertIntoDatabase(DiveLogDatabaseContract.DiveCenters.TABLE_NAME, values);
                newUri = Uri.parse(AUTHORITY + "/" + PATH_CENTERS + "/" + id);
                break;
            case MATCH_COUNTRIES:
                id = insertIntoDatabase(DiveLogDatabaseContract.DiveCountries.TABLE_NAME, values);
                newUri = Uri.parse(AUTHORITY + "/" + PATH_COUNTRIES + "/" + id);
                break;
            case MATCH_LOCATIONS:
                id = insertIntoDatabase(DiveLogDatabaseContract.DiveLocations.TABLE_NAME, values);
                newUri = Uri.parse(AUTHORITY + "/" + PATH_LOCATIONS + "/" + id);
                break;
            case MATCH_ORGANIZATIONS:
                id = insertIntoDatabase(DiveLogDatabaseContract.DiveOrganizations.TABLE_NAME, values);
                newUri = Uri.parse(AUTHORITY + "/" + PATH_ORGANIZATIONS + "/" + id);
                break;
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
        Context context = getContext();
        ContentResolver resolver = context.getContentResolver();
        resolver.notifyChange(uri, null);
        return newUri;
    }

    private long insertIntoDatabase(String table, ContentValues values) {
        SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
        long id = db.insert(
                table,
                null,
                values
        );
        return id;
    }

    @Override
    public String getType(Uri uri) {
        switch (sUriMatcher.match(uri)) {
            case MATCH_DIVERS:
                return "vnd.android.cursor.dir/vnd.com.boyadegroot.divers";
            case MATCH_DIVERS_COUNT:
                return "vnd.android.cursor.item/vnd.com.boyadegroot.diverscount";
            case MATCH_DIVER_ID:
                return "vnd.android.cursor.item/vnd.com.boyadegroot.diver";
            case MATCH_DIVERSTATS_TOTALBOTTOMTIME:
            case MATCH_DIVERSTATS_MINIMALSI:
            case MATCH_DIVERSTATS_DEEPESTDIVE:
            case MATCH_DIVERSTATS_SHALLOWESTDIVE:
            case MATCH_DIVERSTATS_COLDESTDIVE:
            case MATCH_DIVERSTATS_WARMESTDIVE:
                return "vnd.android.cursor.item/vnd.com.boyadegroot.statistic";
            case MATCH_DIVERRES_LOCATIONS:
                return "vnd.android.cursor.dir/vnd.com.boyadegroot.locations";
            case MATCH_DIVES:
                return "vnd.android.cursor.dir/vnd.com.boyadegroot.dives";
            case MATCH_DIVES_COUNT:
                return "vnd.android.cursor.item/vnd.com.boyadegroot.divescount";
            case MATCH_DIVE_ID:
                return "vnd.android.cursor.item/vnd.com.boyadegroot.dive";
            case MATCH_SAMPLES:
                return "vnd.android.cursor.dir/vnd.com.boyadegroot.samples";
            case MATCH_SAMPLES_COUNT:
                return "vnd.android.cursor.item/vnd.com.boyadegroot.samplescount";
            case MATCH_SAMPLE_ID:
                return "vnd.android.cursor.item/vnd.com.boyadegroot.sample";
            case MATCH_CERTS:
                return "vnd.android.cursor.dir/vnd.com.boyadegroot.certifications";
            case MATCH_CERTS_COUNT:
                return "vnd.android.cursor.item/vnd.com.boyadegroot.certificationscount";
            case MATCH_CERT_ID:
                return "vnd.android.cursor.item/vnd.com.boyadegroot.certification";
            case MATCH_SITES:
                return "vnd.android.cursor.dir/vnd.com.boyadegroot.sites";
            case MATCH_SITES_COUNT:
                return "vnd.android.cursor.item/vnd.com.boyadegroot.sitescount";
            case MATCH_SITE_ID:
                return "vnd.android.cursor.item/vnd.com.boyadegroot.site";
            case MATCH_TRIPS:
                return "vnd.android.cursor.dir/vnd.com.boyadegroot.trips";
            case MATCH_TRIPS_COUNT:
                return "vnd.android.cursor.item/vnd.com.boyadegroot.tripscount";
            case MATCH_TRIP_ID:
                return "vnd.android.cursor.item/vnd.com.boyadegroot.trip";
            case MATCH_BUDDIES:
                return "vnd.android.cursor.dir/vnd.com.boyadegroot.buddies";
            case MATCH_BUDDIES_COUNT:
                return "vnd.android.cursor.item/vnd.com.boyadegroot.buddiescount";
            case MATCH_BUDDY_ID:
                return "vnd.android.cursor.item/vnd.com.boyadegroot.buddy";
            case MATCH_COURSES:
                return "vnd.android.cursor.dir/vnd.com.boyadegroot.courses";
            case MATCH_COURSES_COUNT:
                return "vnd.android.cursor.item/vnd.com.boyadegroot.coursescount";
            case MATCH_COURSE_ID:
                return "vnd.android.cursor.item/vnd.com.boyadegroot.course";
            case MATCH_CENTERS:
                return "vnd.android.cursor.dir/vnd.com.boyadegroot.centers";
            case MATCH_CENTERS_COUNT:
                return "vnd.android.cursor.item/vnd.com.boyadegroot.centerscount";
            case MATCH_CENTER_ID:
                return "vnd.android.cursor.item/vnd.com.boyadegroot.center";
            case MATCH_COUNTRIES:
                return "vnd.android.cursor.dir/vnd.com.boyadegroot.countries";
            case MATCH_COUNTRIES_COUNT:
                return "vnd.android.cursor.item/vnd.com.boyadegroot.countriescount";
            case MATCH_COUNTRY_ID:
                return "vnd.android.cursor.item/vnd.com.boyadegroot.country";
            case MATCH_LOCATIONS:
                return "vnd.android.cursor.dir/vnd.com.boyadegroot.locations";
            case MATCH_LOCATIONS_COUNT:
                return "vnd.android.cursor.item/vnd.com.boyadegroot.locationscount";
            case MATCH_LOCATION_ID:
                return "vnd.android.cursor.item/vnd.com.boyadegroot.location";
            case MATCH_ORGANIZATIONS:
                return "vnd.android.cursor.dir/vnd.com.boyadegroot.organizations";
            case MATCH_ORGANIZATIONS_COUNT:
                return "vnd.android.cursor.item/vnd.com.boyadegroot.organizationscount";
            case MATCH_ORGANIZATION_ID:
                return "vnd.android.cursor.item/vnd.com.boyadegroot.organization";
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
    }
}
